﻿/*
 * Сделано в SharpDevelop.
 * Пользователь: CrMosk
 * Дата: 10.05.2013
 * Время: 13:09
 *  
 */
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;

namespace Region.Utils
{
  /// <summary>
  /// Класс MEMStream является стандартным потоком,  данные потока хранятся в оперативной памяти, память выделяется по мере необходимости с заданым шагом
  /// </summary>
  class MEMStream : Stream
  {
    List<Byte[]> Buffers = new List<Byte[]>();
    Int32 m_BuffSize;
    Int32 m_Position = 0;
    Int32 m_Size = 0;
    Int32 m_MaxSize = 0;
    public MEMStream() { m_BuffSize = 64 * 1024; }
    public MEMStream(Int32 BuffSize) { m_BuffSize = BuffSize; }
    public MEMStream(Byte[] Buff) { Buffers.Add(Buff); m_BuffSize = Buff.Length; m_MaxSize = m_BuffSize; m_Size = m_BuffSize; }
    public override bool CanRead{get{ return true; }}
    public override bool CanSeek{get{ return true; }}
    public override bool CanWrite{get{ return true; }}
    public override void Flush(){}
    public override long Length{get { return m_Size; }}
    public override long Position { get { return m_Position; } set { m_Position = (Int32)(value > m_Size ? m_Size : value); } }
    public override int Read(byte[] buffer, int offset, int count)
    {
        Int32 read=0;
        for (; read < count && read + m_Position<m_Size; )
        {
            Int32 Block = ((m_Position + read) / m_BuffSize);
            Int32 Offset = (m_Position + read) % m_BuffSize;
            Int32 Size = ((count - read > m_BuffSize - Offset) ? m_BuffSize - Offset : count - read);
            if (m_Position + read + Size > m_Size) Size = m_Size - (m_Position + read);
            if (Block >= Buffers.Count && Size > 0) return read;
            if (Size == m_BuffSize) 
            {              
              Int32 S = Buffers[Block].Length;
              var BB = Buffers[Block];
              for(int i=0;i<S;i++) buffer[i + offset + read] =  BB[i + Offset];
             //   Buffers[Block].CopyTo(buffer, Offset+offset + read);
            }
            else 
            {
              var BB = Buffers[Block];
              for(int i=0;i<Size;i++)
                buffer[i+offset+read] = BB[i + Offset];              
            }
            read += Size;

        }
        m_Position = m_Position + read;
        return read;
    }
    public override long Seek(long offset, SeekOrigin origin)
    {
        if (origin == SeekOrigin.Begin) m_Position = (Int32)offset;
        else if (origin == SeekOrigin.Current) m_Position = (Int32)(m_Position + offset);
        else m_Position = (Int32)(m_Size + offset);
        return m_Position;
    }
    public override void SetLength(long value){throw new NotImplementedException();}
    public override void Write(byte[] buffer, int offset, int count)
    {
        Int32 write = 0;
        if (m_Position+count>65536)
        {;}
        for (; write < count; )
        {
            Int32 Block = (Int32)((m_Position + write) / m_BuffSize);
            Int32 Offset = (Int32)(m_Position + write) % m_BuffSize;
            Int32 Size = (Int32)((count - write > m_BuffSize - Offset) ? m_BuffSize - Offset : count - write);
            if (Size == m_BuffSize) 
            {
                if (Block >= Buffers.Count && Size > 0) { Buffers.Add(null); m_MaxSize += m_BuffSize; }
                Buffers[Block] = new byte[Size];
                var Buff = Buffers[Block];
                for(int i=0;i<Size;i++) Buff[i] = buffer[i + write + offset];
                //Buffers[Block] = buffer.Skip(write + offset).Take(Size).ToArray(); 
            }
            else
            {
                if (Block >= Buffers.Count && Size > 0) { Buffers.Add(new Byte[m_BuffSize]); m_MaxSize += m_BuffSize; }                
                var Buff = Buffers[Block];
                for(int i=0;i<Size;i++) Buff[i+Offset] = buffer[i + write + offset];
                //buffer.Skip(write + offset).Take(Size).ToArray().CopyTo(Buffers[Block], Offset);
            }
            write += Size;
            m_Size = Math.Max(m_Size, m_Position + write);
        }
        m_Position = m_Position + write;
        return ;
    }
  }
}
